home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / pctmay86.arc / REGULAR.PAS < prev    next >
Pascal/Delphi Source File  |  1986-03-04  |  6KB  |  171 lines

  1. PROGRAM regular;
  2. {
  3.    Search input lines for regular expressions.  Similar to DOS 
  4.    "FIND.EXE" and UNIX "GREP".  Reads from standard input, writes
  5.    to standard output.  Usage: C:>DIR | REGULAR PAS
  6. }
  7.  
  8. CONST
  9.    {                REGULAR EXPRESSION OPERATORS                    }
  10.    CLOSURE = '*';
  11.    BOL = '^';           { match starting at beginning of line        }
  12.    EOL = '$';           { match at end of line                      }
  13.    ANY = '.';           { match any single character                }
  14.    CCL = '[';           { begin character class                     } 
  15.    CCLEND = ']';        { end character class                       }
  16.    NEGATE = '^';        { signify negative character class          }
  17.    NCCL = '!';          { negative character class: internal form   }
  18.    LITCHAR = '@';       { next character not an operator            }
  19.    ESCAPE = '\';        { treat next operator as literal character  }
  20.    DASH = '-';          { consecutive range within class            }
  21.  
  22.    EOF_NUM=255;   { end of file }
  23.    EOLN1_NUM=13;  { return }
  24.    EOLN2_NUM=10;  { line feed }
  25.    ENDSTR = ^A;   { End String: internal code for end of line       }
  26.  
  27.  
  28.  
  29.  
  30. {$I InOut.pas} { Get line from Standard Input, Put line to STDOUT }
  31.  
  32. var ARG,             { input string: regular expression  }
  33.     LIN,             { line from standard input          }
  34.     PAT: maxstr;     { regular expression (internal form)}
  35.  
  36. {$I Compile.pas}     { compile regular expression to internal form }
  37.  
  38. function locate(c: char; pat: maxstr; offset: integer) : boolean;
  39. {
  40.    Search for the character C in the character class at pat[offset] 
  41. }
  42. var i: integer;
  43. begin
  44.     { size of class is at pat[offset], characters follow }
  45.     locate:=true;
  46.     i:=offset+ord(pat[offset]);  {last position in class}
  47.     while i>offset do
  48.       if c=pat[i] then exit else i:=i-1;
  49.     locate:=false;
  50. end;
  51.  
  52. function lin_advance(lin: maxstr; l: integer; 
  53.                             pat: maxstr; p: integer): integer;
  54. {
  55.    Matches character pattern pat[p] against input line characters 
  56.    starting at lin[l].  LIN_ADVANCE=-1 means no match.
  57. }
  58.  
  59. begin
  60.   lin_advance:=-1;
  61.   case pat[p] of
  62.             LITCHAR: if lin[l]=pat[p+1] then lin_advance:=1;
  63.                 BOL: if l=1 then lin_advance:=0;
  64.                 ANY: if l<length(lin) then lin_advance:=1;
  65.                 EOL: if l=length(lin) then lin_advance:=0;
  66.                 CCL: if locate(lin[l], pat, p+1)
  67.                                  then lin_advance:=1;
  68.                NCCL: if (l<length(lin)) and
  69.                         (not (locate(lin[l], pat, p+1)))
  70.                              then lin_advance:=1;
  71.                  else error('in lin_advance: can''t happen')
  72.              end; {case}
  73. end;
  74.  
  75. function pat_advance(pat: maxstr; p: integer) : integer;
  76.   Returns offset of next pattern within PAT string.  Current pattern
  77.   starts at PAT[P].  ex.  if pat="@c@a@t" and p=1 then pat_advance=3.
  78. }
  79. begin
  80.    case pat[p] of
  81.       LITCHAR: pat_advance:=p+2;
  82.       BOL,EOL,ANY: pat_advance:=p+1;
  83.       CCL,NCCL: pat_advance:=p+ord(pat[p+1])+2;
  84.       CLOSURE: pat_advance:=p+1;
  85.          else error('in pat_advance: can''t happen');
  86.      end; {case}
  87. end;
  88.  
  89. function amatch (lin: maxstr; offset: integer; 
  90.                    pat: maxstr; p: integer): boolean; forward;
  91.  
  92. function match_closure(lin: maxstr; offset:integer; 
  93.                             pat:maxstr; p:integer): integer;
  94. {
  95.    Match as many characters as possible with closure.
  96.    Does rest of pattern match remaining characters on line?
  97.    If not, shorted closure match by one and try again.
  98.    If closure shortened to 0, no match is possible (match_closure=-1)
  99. }
  100. var n, backtrack, increment: integer;
  101. begin
  102.   match_closure:=0;
  103.   n:=offset;
  104.   repeat
  105.       increment:=lin_advance(lin,n,pat,p);
  106.       if increment>=0 then n:=n+increment;
  107.   until ((increment<0) or (n>length(lin)));
  108.   if n=offset then exit;                 { closure length is zero }
  109.   for backtrack:=n downto offset do
  110.       begin
  111.              if amatch(lin,backtrack,pat,pat_advance(pat,p)) then
  112.                 begin
  113.                   match_closure:=backtrack;
  114.                   exit;
  115.                 end;
  116.       end;
  117.    match_closure:=-1;
  118. end;
  119.  
  120. function amatch;
  121. {
  122.    Anchored match.  Does pattern PAT match input line starting at
  123.    LIN[offset]?  Loop through PAT distinguishing the two cases; 
  124.    if PAT[P] is a closure, find appropriate closure size to match.
  125.    Otherwise, just compare characters and update PAT and LIN indexes.
  126. }
  127. var l,increment, closure_end: integer;
  128.  
  129. begin
  130.      amatch:=false;
  131.      l:=offset;
  132.      while (p<=length(pat)) do
  133.         begin
  134.           if l>length(lin) then exit;
  135.           if pat[p]=CLOSURE then
  136.            begin
  137.              closure_end:=match_closure(lin,l,
  138.                          pat,pat_advance(pat,p));  { jump over "*" }
  139.              if closure_end<0 then exit;
  140.              l:=closure_end;
  141.              p:=pat_advance(pat,p);
  142.            end
  143.             else
  144.                 begin
  145.                   increment:=lin_advance(lin,l,pat,p);
  146.                   if increment<0 then exit;
  147.                   l:=l+increment;
  148.                 end;
  149.             p:=pat_advance(pat,p);
  150.           end; {while}
  151.      amatch:=true;
  152. end;
  153.  
  154. function match(lin,pat: maxstr): boolean;
  155. {
  156.    Loop through input line checking for match at each position.
  157. }
  158. var i: integer;
  159. begin
  160.   match:=true;
  161.   for i:=1 to length(lin) do if amatch(lin,i,pat,1) then exit;
  162.   match:=false;
  163. end;
  164.  
  165. begin
  166.  if not getarg(arg) then error('no pattern specified');
  167.  pat:=makepat(arg);
  168.  while getline(lin) do 
  169.          if match(lin,pat) then putline(lin);
  170. end.